﻿using Microsoft.Hadoop.Client;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using ViewMaker;
using ViewMaker.Core;

namespace HDInsightStudio
{
    public class JobViewModelBase : ViewModelBase
    {
        public HdInsightConfig Config { get; private set; }

        public string JobId
        {
            get { return _JobId; }
            set { _JobId = value; OnPropertyChanged("JobId"); }
        }
        private string _JobId;

        public string Status
        {
            get { return _status; }
            set { _status = value; OnPropertyChanged("Status"); }
        }
        private string _status;


        public JobViewModelBase(string jobId)
        {
            Config = HdInsightConfig.Instance;
            this.JobId = jobId;
        }

        public JobStatusCode JobStatusCode
        {
            get { return _jobStatusCode; }
            set { _jobStatusCode = value; OnPropertyChanged("JobStatusCode"); }
        }
        private JobStatusCode _jobStatusCode;

        protected void WaitForJobCompletion(JobCreationResults jobDetails, Func<JobDetails, bool> progressCallback = null, int pollingInterval=3000)
        {
            var jobInProgress = Config.JobClient.GetJob(jobDetails.JobId);
            JobStatusCode = jobInProgress.StatusCode;
            if (progressCallback != null)
            {
                if (!progressCallback(jobInProgress)) return;
            }
            while (jobInProgress.StatusCode != JobStatusCode.Completed && jobInProgress.StatusCode != JobStatusCode.Failed)
            {
                Thread.Sleep(pollingInterval);
                jobInProgress = Config.JobClient.GetJob(jobInProgress.JobId);
                JobStatusCode = jobInProgress.StatusCode;
                if (progressCallback != null)
                {
                    if (!progressCallback(jobInProgress)) return;
                }
            }
        }

        protected string ReadOutput(string encoding = "ASCII")
        {
            var output = Status + (Status.EndsWith("/") ? "" : "/" )+ "stdout";

            return GetHeadText(output, 1000 * 1000 * 2, encoding);
        }

        protected string ReadError(string encoding = "ASCII")
        {
            var output = Status + (Status.EndsWith("/") ? "" : "/") + "stderr";

            return GetHeadText(output, 1000 * 1000 * 2, encoding);
        }

        public string GetHeadText(string path, int readSize, string encoding = "ASCII")
        {
            try
            {
                using (var st = new MemoryStream())
                {
                    using (var stream = Config.HdfsClient.OpenFile(path, 0, readSize).WaitForResult().Content.ReadAsStreamAsync().WaitForResult())
                    {
                        Byte[] buff = new Byte[1024 * 1024];
                        while (true)
                        {
                            var size = stream.Read(buff, 0, buff.Length);
                            if (size <= 0) break;
                            st.Write(buff, 0, size);
                        }
                        Encoding enc = Encoding.GetEncoding(encoding);
                        int i;
                        for (i = 0; i < buff.Length; i++)
                        {
                            if (buff[i] == 0) break;
                        }
                        return enc.GetString(buff, 0, i);
                    }
                }
            }
            catch
            {
                return null;
            }
        }

        protected JObject LoadData()
        {
            var file = this.ShowOpenTextFile("*.txt|*.txt");
            if (file == null) return null;
            using (file)
            {
                return JObject.Parse(file.ReadToEnd());                
            }
        }
        protected void SaveData(JObject data)
        {
            var file = this.ShowSaveTextFile("*.txt|*.txt");
            if (file == null) return;
            using (file)
            {
                file.Write(data.ToString());
            }
        }

        public ICommand SaveCommand
        {
            get { return this.CreateCommand(Save); }
        }
        public ICommand LoadCommand
        {
            get { return this.CreateCommand(Load); }
        }

        protected virtual void Save()
        {
        }
        protected virtual void Load()
        {
        }

        public ICommand CloseCommand
        {
            get { return this.CreateViewCommand(ViewCommands.Close); }
        }

    }
}
